/**
 * convertDataToModuleTree函数的升级版，不仅可以将模块数据变成树状的结构，
 * 并且在每个模块数据上增加了parentIds属性，该属性为当前模块所有上层节点组成的数组（不含当前模块的id，元素为由顶层节点开始到当前节点的父节点结束组成的数组）
 * @param {*} data 同convertDataToModuleTree的参数data
 */
function covertDataToCascaderTree(data) {
	var root = [],
		o = {};

	function add(arr, topic, parenttopic) {
		var obj = JSON.parse(JSON.stringify(topic));
		obj.children = [];
		if (!obj.parentIds) obj.parentIds = [];
		if (parenttopic) {
			obj.parentIds = [].concat(parenttopic.parentIds);
			obj.parentIds.push(parenttopic.id + "");
		}
		o[obj.id] = obj;
		obj.parent = parenttopic;
		arr.push(obj);
	}
	if (data instanceof Array) {
		data.forEach(item => {
			if (o[item.pid]) {
				add(o[item.pid].children, item, o[item.pid]);
			} else {
				add(root, item, undefined);
			}
		});
	}
	o = null;
	//使用递归删除children为空的属性
	function cleanChildren(__subject) {
		if (__subject.children && __subject.children.length == 0) {
			delete __subject.children;
		} else {
			for (let j = 0; j < __subject.children.length; j++) {
				cleanChildren(__subject.children[j])
			}
		}

	}

	for (let i = 0; i < root.length; i++) {
		let _subject = root[i];
		cleanChildren(_subject)
	}

	return root;
}

/**
 * 在模块列表数据中查找某个id的模块的上级模块组成的数组，返回值为从顶层模块开始到当前id模块父模块结束组成的数组
 * @param {*} id 要查找的模块id
 * @param {*} data 同convertDataToModuleTree的参数data
 */
function getParentIdArr(id, data, option = {
	id: 'id',
	pid: 'pid'
}) {
	function foo(data) {
		for (var k in data) {
			line[data[k][option.id]] = data[k];
			if (data[k].children) {
				foo(data[k].children);
			}
		}
	}

	function getParents(id) {
		var res = [];
		if (!line[id]) return res;
		res.push(line[id][option.id])
		return res.concat(getParents(line[id][option.pid]));
	}
	var line = {};
	foo(data)
	// console.log(line); //穿线
	var r = getParents(id);
	// console.log(r);
	// console.log(r.reverse(),r);
	return r.reverse()
}

/**
 * 通过模块树型结构按照关键字查找
 * @param {array} moduleNode 从哪个模块的根节点开始查找，不可
 * @param {} key 
 * @param {*} value 
 */
function searchModulesTree(tree, key, value) {
	tree = JSON.parse(JSON.stringify(tree))
	let searchTree = function (node, index, value, removeArr, replaceStr, regExp) {
		// if( !node ) return;
		let children = node.children
		//针对非叶子节点，需要递归其children节点
		if (children && children.length > 0) {
			let innderArr = []
			for (let i = 0; i < children.length; i++) {
				searchTree(children[i], i, value, innderArr, replaceStr, regExp)
			}
			//如果当前节点不满足搜索条件，则对其children不满足条件的节点执行删除操作
			if (node[key].indexOf(value) === -1) {
				for (let j = innderArr.length - 1; j >= 0; j--) {
					children.splice(innderArr[j], 1)
				}
				/*
				 *children节点删除结束后，如果children length为0，
				 *并且当前节点也不满足搜索条件，则当前节点也加入删除数组
				 */
				if (node.children.length === 0) {
					removeArr.push(index)
				}
			} else {
				//当前节点非叶子节点，将满足条件内容做标记显示
				node[key] = node[key].replace(regExp, replaceStr)
			}
		} else {
			//叶子节点，直接进行匹配
			if (node[key].indexOf(value) === -1) {
				removeArr.push(index)
			} else {
				//将满足条件内容做标记显示
				node[key] = node[key].replace(regExp, replaceStr)
			}
		}
	}
	//不满足搜索条件的待删除元素索引数组
	let removeArr = []
	// eslint-disable-next-line no-eval
	//replace时正则匹配，全局匹配 
	// eval('/' + value + '/g')
	const globalEval = eval;
	let regExp = globalEval('/' + value + '/g')
	//满足条件的字符串匹配为以下内容，红色显示，可以根据自己需要调整以下字符串
	let replaceStr = `<span class='red'>${value}</span>`
	for (let i = 0; i < tree.length; i++) {
		let node = tree[i]
		searchTree(node, i, value, removeArr, replaceStr, regExp)
	}
	//遍历删除不满足条件的节点
	for (let j = removeArr.length - 1; j >= 0; j--) {
		tree.splice(removeArr[j], 1)
	}
	return tree;
}
/**
 * @author: ddhhh
 * @param {*} func
 * @param {*} wait
 * @param {*} immediate
 * @return {*}
 * @description: Description
 * @Date: 2020-12-09 16:00:55
 */
function debounce(func, wait, immediate) {
	let timeout, args, context, timestamp, result

	const later = function () {
		// 据上一次触发时间间隔
		const last = +new Date() - timestamp

		// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
		if (last < wait && last > 0) {
			timeout = setTimeout(later, wait - last)
		} else {
			timeout = null
			// 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
			if (!immediate) {
				result = func.apply(context, args)
				if (!timeout) context = args = null
			}
		}
	}

	return function (...args) {
		context = this
		timestamp = +new Date()
		const callNow = immediate && !timeout
		// 如果延时不存在，重新设定延时
		if (!timeout) timeout = setTimeout(later, wait)
		if (callNow) {
			result = func.apply(context, args)
			context = args = null
		}

		return result
	}
}

function factorial(n) {
	let list = [];
	for (let i = 0, l = n.length; i < l; i++) {
		if (!n[i].children || !n[i].children.length) {
			list.push(n[i]);
		} else {
			list = [...list, n[i], ...factorial(n[i].children)];
		}
	}
	return list;
}
/**
 * @author: ddhhh
 * @param {*} malfunction 故障数
 * @param {*} total 总数
 * @param {*} option 配置项 x:原点x左边  y:圆点y坐标 r: 圆半径
 * @param {*} complementary 是否设置互补元素
 * @return {*}
 * @description: Description
 * @Date: 2021-01-28 10:08:41
 */
function getSymbalPath(malfunction, total, option = {
	x: 150,
	y: 150,
	r: 150
}, complementary = false) {
	let Delta = malfunction <= total / 2 ? 1 : 0; //大弧（1）还是小弧（0）
	const {
		x,
		y,
		r
	} = option;
	let Theta = (malfunction / total) * Math.PI * 2; //求出弧度 θ
	let endX = x - Math.sin(Theta) * r;
	let endY = y - Math.cos(Theta) * r;
	let path = `M${x},${y} L${x} ${
		y - r
	} A${r},${r} 0 ${Delta},1 ${endX},${endY} z`;
	if (complementary) {
		path += `M${x},${y} L${x} ${
			y - r
		} A${r},${r} 0 ${Number(!Delta)},0 ${endX},${endY} z`;
	}
	return `path://${path}`;
}

function isIE() {
	const bw = window.navigator.userAgent
	const compare = (s) => bw.indexOf(s) >= 0
	const ie11 = (() => 'ActiveXObject' in window)()
	return compare('MSIE') || ie11
}
/**
 * 
 * @param {timeObj} val
 * @author ddhhh
 * @description 2019-06-05 08:01:01
 *  
 */
function formatterDate(val) {
	// if(!val){return "-"}
	let _d = val ? new Date(val) : new Date();
	return (
		_d.getFullYear() +
		"-" +
		(_d.getMonth() > 8 ? _d.getMonth() + 1 : "0" + (_d.getMonth() + 1)) +
		"-" +
		(_d.getDate() > 9 ? _d.getDate() : "0" + _d.getDate()) +
		" " +
		(_d.getHours() > 9 ? _d.getHours() : "0" + _d.getHours()) +
		":" +
		(_d.getMinutes() > 9 ? _d.getMinutes() : "0" + _d.getMinutes()) +
		":" +
		(_d.getSeconds() > 9 ? _d.getSeconds() : "0" + _d.getSeconds())
	);
}
/**
 * 
 * @param {timeObj} val
 * @author ddhhh
 * @description 2019/06/05
 *  
 */
function formatterDateBySlash(val, style = '/') {
	let _d = val ? new Date(val) : new Date();
	return (
		_d.getFullYear() +
		style +
		(_d.getMonth() > 8 ? _d.getMonth() + 1 : "0" + (_d.getMonth() + 1)) +
		style +
		(_d.getDate() > 9 ? _d.getDate() : "0" + _d.getDate())
	);
}

/**
 * @author: ddhhh
 * @param {*} timeDiff 时间毫秒差 
 * @return {*} "xx天x小时xx分xx秒"
 * @description: 格式化时间间隔
 * eg: 1244390400 => "14天9小时39分50秒"
 * @Date: 2021-07-15 14:07:38
 */
function formatterTimeDiff(timeDiff) {
	return (Math.floor(timeDiff / 86400000) ? `${Math.floor(timeDiff / 86400000)}天` : '') +
		(Math.floor((timeDiff % 86400000) / 3600000) ? `${Math.floor((timeDiff % 86400000) / 3600000)}小时` : '') +
		(Math.floor((timeDiff % 3600000) / 60000) ? `${Math.floor((timeDiff % 3600000) / 60000)}分` : '') +
		(Math.floor((timeDiff % 60000) / 1000) ? `${Math.floor((timeDiff % 60000) / 1000)}秒` : '')
}
/**
 * @param {*} url
 * @bricklayer ddhhh
 * @description 获取URL参数
 */
function getSearch(url) {
	const search = url.split('?')[1]
	if (!search) {
		return {}
	}
	return JSON.parse('{"' + decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}')
}
/**
 * @author: ddhhh
 * @param {*}
 * @return {*}
 * @description: 获取iframe层级,默认从顶层开始，只适用于当前文档（不包括嵌套的文档）中只存在一个iframe的场景
 * @Date: 2021-10-21 16:43:54
 */
function getIframRect(w = top) {
	function getRect(win) {
		let arr = []
		let _win = win.document.getElementsByTagName('iframe')
		if (_win.length) {
			return arr.concat(_win[0].getBoundingClientRect().toJSON(), getRect(_win[0].contentWindow))
		} else return arr
	}
	return getRect(w).reduce((t, i) => {
		Object.keys(i).forEach(item => {
			t[item] = (t[item] || 0) + i[item]
		})
		return t
	}, {})
}
/**
 * @author: ddhhh
 * @param {*} val
 * @return {*}
 * @description: 校验是否为空值
 * @Date: 2022-03-28 19:29:43
 */
function isEmpty(val) {
  // null or undefined
  if (val == null) return true;

  if (typeof val === 'boolean') return false;

  if (typeof val === 'number') return !val;

  if (val instanceof Error) return val.message === '';

  switch (Object.prototype.toString.call(val)) {
    // String or Array
    case '[object String]':
    case '[object Array]':
      return !val.length;

    // Map or Set or File
    case '[object File]':
    case '[object Map]':
    case '[object Set]': {
      return !val.size;
    }
    // Plain Object
    case '[object Object]': {
      return !Object.keys(val).length;
    }
  }

  return false;
}
/*深拷贝*/
function deepClone(val){
	let arr = val;
	let arr1 = undefined;
	if(dataType(val)=='array'){
		arr1 = [];
		val.forEach(item=>{
			arr1.push(deepClone(item));
		})
	}else if(dataType(val)=='object'){
		arr1 = {};
		for(let key in val){
			arr1[key] = deepClone(arr[key]);
		}
		// arr1 = {...arr};
	}else {
		arr1 = arr;
	}
	return arr1;
}
function dataType(val){
	let typeList = {
		'[object Null]':'null',
		'[object Date]':'date',
		'[object Array]':'array',
		'[object Object]':'object'
	};
	let type = "";
	if(typeof val =='object'){
		type = typeList[Object.prototype.toString.call(val)];
	}else{
		type = typeof val
	}
	return type;
}
export {
	covertDataToCascaderTree,
	getParentIdArr,
	searchModulesTree,
	debounce,
	factorial,
	getSymbalPath,
	isIE,
	formatterDate,
	formatterDateBySlash,
	formatterTimeDiff,
	getSearch,
	getIframRect,
	isEmpty,
	deepClone
}